﻿using System;
using System.Windows;
using System.Windows.Media.Animation;
using System.Windows.Media.Media3D;
using HelixToolkit.Wpf;
using System.Windows.Media;

namespace GameBoard
{
    public class PictureVisual : RectangleVisual3D, ICharacterVisual<PictureVisualData>, IFlip, ICanBeTranslucent
    {
        bool _belongsToMoveablePicture = false;
        public bool BelongsToMoveablePicture
        {
            get { return _belongsToMoveablePicture; }
        }
        private double _pictureOffset;
        public void MoveTo(Point3D newPoint, TimeSpan duration)
        {
            var adjustForOffset = FindPicturePoint(_longestSide, newPoint);
            var moveAnimationPic =
               new Point3DAnimation(Origin, adjustForOffset, duration);
            AnimationClock clock1 = moveAnimationPic.CreateClock();
            ApplyAnimationClock(OriginProperty, clock1);
        }
        internal static Point3D FindPicturePoint(double longestPictureSide, Point3D originalPoint)
        {
            var ret = new Point3D(originalPoint.X, originalPoint.Y, originalPoint.Z);
            ret.Z += longestPictureSide/2;
            ret.Z += MoveablePicture.ConeHeight;
            return ret;
        }
      
        static Vector3D _topViewVector = new Vector3D(0, 0, 1);
        static Vector3D _sideViewVector = new Vector3D(0, -1, 0);
        private void SetToFirstView()
        {
            Normal = _topViewVector;
            IsTopDown = true;
        }
        private double _longestSide;
        public void PopulateVisualData(BaseVisualData theData)
        {
            _belongsToMoveablePicture = theData.BelongsToMoveablePicture;
            FactoryID = theData.FactoryID;

            var pd = theData as PictureVisualData;
            var fileName = pd.MaterialFile;
            ImageBrush frontBrush = MaterialMaker.MakeImageMaterial(fileName);
            Material frontMaterial = new DiffuseMaterial(frontBrush);
            Material = frontMaterial;
            BackMaterial = frontMaterial;
            Length = pd.Length;
            Width = pd.Width;
            _longestSide = Length > Width ? Length : Width;
            LengthDirection = pd.LengthDirection;
            _sideViewLengthDirection = new Vector3D(LengthDirection.X, LengthDirection.Y, LengthDirection.Z);
            _topDownLengthDirection = 
                new Vector3D(-LengthDirection.X, -LengthDirection.Y, -LengthDirection.Z);
            Normal = pd.Normal;
            Origin = FindPicturePoint(Length, pd.Origin);
            SetToFirstView();
            
            TranslucentMaterialMaker.MakeMaterialsFromBrush(frontBrush, this, false);
        }

        public ModelVisual3D VisualElement
        {
            get { return this; }
        }


        public Guid FactoryID { get; set; }

        public void ToggleToTopDownViewMode()
        {
            if (IsTopDown || !_hasFlippedUp)
            {
                return;
            }
            Normal = _topViewVector;
            //var fixer = new Point3D(Origin.X, Origin.Y, Origin.Z - _longestSide);
            //For some unknowable reason, just changing the origin was failing
            //MoveTo(fixer, new Duration(TimeSpan.FromSeconds(0)));
            LengthDirection = _sideViewLengthDirection;
            IsTopDown = true;
        }
        bool _hasFlippedUp = false;
        private Vector3D _topDownLengthDirection;
        private Vector3D _sideViewLengthDirection;
        public void ToggleToSideViewMode()
        {
            if (!IsTopDown)
            {
                return;
            }
            _hasFlippedUp = true;
            Normal = _sideViewVector;
            //var fixer = new Point3D(Origin.X, Origin.Y, Origin.Z + (_longestSide));
            //MoveTo(fixer, new Duration(TimeSpan.FromSeconds(0)));
            LengthDirection = _topDownLengthDirection;
            
            IsTopDown = false;
        }


        public bool IsTopDown
        {
            get;
            private set;
        }

        private VisiblityType _opacity;
        public VisiblityType Opacity
        {
            get { return _opacity; }
            set
            {
                _opacity = value;
                TranslucentMaterialMaker.ChangeCurrentMaterialTo(this, _opacity);
            }
        }

        public DiffuseMaterial InvisibleMaterial { get; set; }
        public DiffuseMaterial VisibleMaterial { get; set; }
        public DiffuseMaterial TranslucentMaterial { get; set; }
    }
}